package trim.calc.smdata;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import trim.common.Format;
import trim.common.inputdata.FormatOrder;
import trim.common.inputdata.InputData;
import trim.common.sm.ITrimSMData;
import trim.common.sm.SMColumn;
import trim.common.sm.SimpleTrimSMData;
import trim.common.utils.Utils;

/**
 * ExtensionSMData.java
 * Реализация интерфейса {@link ITrimSMData} для расширенного
 * СМ.
 *
 * Created on 19.11.2008 21:40:40
 * @author Дмитрий
 */
public class ExtensionTrimSMData extends SimpleTrimSMData
{
  //индикатор расширенной задачи
  boolean ext=false;

  public ExtensionTrimSMData(InputData inputData)
  {
    super();
    this.inputData=inputData.clone();
    FormatOrder[] fc=this.inputData.getFormatOrderList().toArray(new FormatOrder[0]);
    Arrays.sort(fc,new Comparator<FormatOrder>() {

      public int compare(FormatOrder o1,FormatOrder o2)
      {
        if(o1.getFormat().getLength()>o2.getFormat().getLength())
          return -1;
        else if(o1.getFormat().getLength()<o2.getFormat().getLength())
          return 1;
        else
          return 0;
      }
    });
    this.inputData.getFormatOrderList().clear();
    this.inputData.getFormatOrderList().addAll(Arrays.asList(fc));
    n=this.inputData.getFormatOrderList().size()+1;
    this.inputData.getFormatOrderList().add(new FormatOrder(new Format(0),0));
    getMemory();
    n--;
    init(this.inputData);

  }

  /**
   * Установка минимального значения целевой функции в расширенной задаче
   * @param minValue минимальное значение целевой функции в расширенной задаче
   */
  public void setObjectiveFunctionMinValue(double minValue/*,double[] objectiveFunction*/)
  {
    init(inputData);
    for (int i=0; i<n; i++)
      X[n][i]=1;
    for (int i=0; i<n; i++)
      X1[n][i]=X1[i][i];
    X[n][n]=-1;
    X1[n][n]=-1;
    Res[n]=-minValue;
    for (int i=0; i<n; i++) {
      Res[n]+=Res[i];//objectiveFunction[i];
    }
    V[n]=0;
    n++;
    ext=true;
  }

  @Override
  public SMColumn getBestColumn(double[] dualVars)
  {
    if (ext)
      n--;

    int[] r1=Utils.getBestPattern_BB(C,dualVars,n,material,1.0-(ext?dualVars[n]:0));
    double rec=0.0;
    double col1[]=new double[n];
    for(int i=0;i<n;i++)
    {
      rec+=dualVars[i]*r1[i];
      col1[i]=r1[i];
    }
    SMColumn col= new SMColumn(rec-1,col1);

    //SMColumn col=super.getBestColumn(dualVars);
    if (!ext)
      return col;
    n++;
    //проверяем столбец (0,0,..,-1);
    if (dualVars[n-1]*-1>col.getEstimation()+dualVars[n-1]) {
      col.setColumn(new double[n]);
      col.getColumn()[n-1]=-1;
      col.setEstimation(dualVars[n-1]*-1);
    } else {
      double r[]=new double[n];
      System.arraycopy(col.getColumn(),0,r,0,n-1);
      r[n-1]=1;
      col.setColumn(r);
      col.setEstimation(col.getEstimation()+dualVars[n-1]);
    }
    return col;
  }

  public List<SMColumn> getZeroCols(double[] dualVars)
  {
    double[] dV=dualVars;
    List<SMColumn> cols=new ArrayList(1000);
    //Cols.push_back(req);
    double est;//оценка снизу
    int k, m;
    double gam;
    int lam;//текущая стоимость и остаток тамбура
    int[] xx=new int[n];//решения
    int i, j, t, count=0;
    double rec=0.0;//достигнутый максимум
    int[] Sort=new int[n];//массив индексов(для сортировки по возрастанию)
    boolean b;
    int clcount=0;
    m=n;
    if (ext)
    {
      m--;
    }
    for (i=0; i<m; i++) {
      xx[i]=0;
      Sort[i]=i;
    }
    for (i=0; i<m-1; i++) {
      t=i;
      for (j=i+1; j<m; j++) {
        t=i;
        if ((dV[Sort[j]]/(double) C[Sort[j]])-(dV[Sort[t]]/(double) C[Sort[t]])>1*1e-19) {
          t=j;
          m=Sort[i];
          Sort[i]=Sort[t];
          Sort[t]=m;
        }
      }
    }
    m=n;
    if (ext)
      m--;
    lam=S;
    gam=0.0;
    rec=1.0;
    if (ext)
      rec-=dV[m];
    k=-1;
//mkest:

    do {
      while (k!=m-1&&clcount<100000) {
        k++;

        if (C[Sort[k]]>lam)
          continue;
        est=gam+(double) lam*dV[Sort[k]]/(double) C[Sort[k]];
        if (est<=rec-1e-13)
          break;
        t=(int) (lam/C[Sort[k]]);
        if ((count+t)>=KnifeCount)
          t=KnifeCount-1-count;
        count+=t;
        xx[Sort[k]]=xx[Sort[k]]+t;
        gam=gam+t*dV[Sort[k]];
        lam=lam-t*C[Sort[k]];

        if (t>0&&(Math.abs(gam-rec)<1e-13)&&((lam<=mint)||(lam>=maxt))) {
          clcount++;
          double[] c=new double[m+1];
          cols.add(new SMColumn(0,c));
          for (i=0; i<m; i++)
            c[i]=xx[i];
          if (ext)
            c[m]=1;
        }
        //if(k==m-1)break;
        continue;
      }

      while (k>=0&&xx[Sort[k]]==0)
        k--;
      if (k>=0) {
        xx[Sort[k]]--;
        count--;
        lam=lam+C[Sort[k]];
        gam=gam-dV[Sort[k]];
        if (xx[Sort[k]]>0&&(Math.abs(gam-rec)<1e-13)&&((lam<=mint)||(lam>=maxt))) {
          clcount++;
          double[] c=new double[m+1];
          //Col=new int[n+1];
          cols.add(new SMColumn(0.0,c));
          for (i=0; i<m; i++)
            c[i]=xx[i];
          if (ext)
            c[m]=1;
        }
      }
    }
    while (k>=0);


    /*m=Cols.size()+n+1;
    int[][] ZCols=new int[n+1][m];

    j=n+1;
    for(int[] col:Cols)
    {
    for(i=0;i<n+1;i++)ZCols[i][j]=col[i];

    j++;
    }
    //Копирование в список первых n из базисной подматрицы
    for(j=0;j<n+1;j++)
    for(i=0;i<n+1;i++)
    ZCols[i][j]=X[i][j];

    return ZCols;*/
    //if(ext)n++;
    return cols;
  }

  @Override
  public int getProblemSize()
  {
    if (ext)
      return super.getProblemSize();
    else
      return super.getProblemSize()-1;
  }
}
